package com.bing.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.Record;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by kaibb on 15-11-26.
 */
public class GoogleIps {

    private static final Logger LOGGER = LoggerFactory.getLogger(GoogleIps.class);

    /**
     * 在answers中查找IP段.
     * eg:
     * _netblocks.google.com.	1942	IN	TXT	"v=spf1 ip4:64.18.0.0/20 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:207.126.144.0/20 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all"
     * <p/>
     * ip4:209.85.128.0
     */
    private static final Pattern IP4S = Pattern.compile("ip4:(?<ip>\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\/\\d{1,2})");

    /**
     * 在answer中查找.
     * eg:
     * _spf.google.com. 124 IN TXT "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"
     */
    private static final Pattern DNAME = Pattern.compile("include:(?<ip>\\S*)");
    public static final String IP = "ip";

    public static final String GOOGLE_IP = "_spf.google.com";

    /**
     * eg: _spf.google.comz
     *
     * @param name
     * @return
     */
    public static List<String> getIPS(String name, TYPE type) {
        List<String> ips = new ArrayList<>();
        Lookup lookup;
        try {
            lookup = new Lookup(name, Type.TXT);
            lookup.run();
            if (lookup.getResult() != Lookup.SUCCESSFUL) {
                LOGGER.error("查找Google IPS ERROR:{} ", lookup.getErrorString());
                return ips;
            }
            Record[] answers = lookup.getAnswers();
            for (Record answer : answers) {
                Matcher matcher;
                switch (type) {
                    case ONE:
                        matcher = DNAME.matcher(answer.toString());
                        break;
                    case TWO:
                        matcher = IP4S.matcher(answer.toString());
                        break;
                    default:
                        throw new RuntimeException();
                }
                while (matcher!=null && matcher.find()) {
                    ips.add(matcher.group(IP));
                }
            }

            if (TYPE.ONE == type) {
                List<String> _ip = new ArrayList<>();
                for (String ip : ips) {
                    _ip.addAll(getIPS(ip, TYPE.TWO));
                }
                ips = _ip;
            }
        } catch (TextParseException e) {
            LOGGER.debug("查找Google IPs异常.", e);
        }
        return ips;
    }

    public static void ips2Files(List<String> ips) {
        BufferedWriter bufferedWriter = null;
        for (String ip : ips) {
            long startIp = IpTool.ip2Long(IpTool.getIP(ip, false));
            long endIp = IpTool.ip2Long(IpTool.getIP(ip, true));
            try {
                bufferedWriter = new BufferedWriter(new FileWriter("ips.txt"));
                while (startIp <= endIp) {
                    bufferedWriter.write(IpTool.long2Ip(startIp));
                    bufferedWriter.newLine();
                    startIp++;
                }
            } catch (IOException e) {
                LOGGER.error("", e);
            } finally {
                try {
                    bufferedWriter.flush();
                    bufferedWriter.close();
                } catch (IOException e) {
                    LOGGER.error("", e);
                }
            }
        }
    }

    public static List<String> getIPS() {
        List<String> ips;
        try {
            ips = Files.readAllLines(Paths.get("ipss.txt"));
        } catch (Exception e) {
            LOGGER.error("No IP cache.", e);
            ips = getIPS("_spf.google.com", TYPE.ONE);
            ips2Files(ips);
        }
        return ips;
    }


    public enum TYPE {
        ONE, TWO
    }
}
